from _datetime import datetime
from flask import abort
from flask import current_app, render_template, g, request, jsonify
from info import constants, db
from info.models import User, News, Comment, CommentLike, tb_user_follows
from info.utils.response_code import RET
from . import news_bp
from info.utils.common import user_login_data


# 2.使用蓝图
@news_bp.route('/<int:news_id>')
@user_login_data
def get_news_detail(news_id):
    """显示新闻详情 后端接口"""
    # --------------1. 获取当前登陆的用户信息---------------
    user = g.user
    # --------------2. 获取点击排行,进行展示----------------
    news_list = []
    try:
        news_list = News.query.order_by(News.clicks.desc()).limit(constants.CLICK_RANK_MAX_NEWS)
    except Exception as e:
        current_app.logger.error(e)
    click_news_list = []
    for news in news_list if news_list else None:
        click_news_list.append(news.to_review_dict())

    # --------------3. 查询新闻数据,进行展示----------------
    # 1.查询新闻对象
    try:
        news = News.query.filter(News.id == news_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻数据异常")
    # 如果数据不存在,返回404
    if not news:
        abort(404)
    # 更新点击量
    news.clicks += 1
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="点击量保存异常")
    # 2.将新闻对象转换成字典
    news_dict = news.to_dict()

    # -------------4. 判断新闻是否被收藏-------------------
    is_collected = False
    # 判断用户是否收藏了该条新闻
    if user:
        if news in user.collection_news:
            is_collected = True

    # -------------5. 查询评论数据进行展示------------------
    # 将所有评论转化为字典列表
    try:
        comments_list = Comment.query.filter_by(news_id=news_id).order_by(Comment.create_time.desc())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="真实密码查询异常")
    comments_dict_list = []
    for comment in comments_list:
        comments_dict_list.append(comment.to_dict())

    # ------------6. 查询当前用户被哪些评论点过赞------------
    # 根据评论id和用户id查询出对应的CommentLike对象
    if user:
        for comment_dict in comments_dict_list:
            try:
                comment_like_obj = CommentLike.query.filter_by(comment_id=comment_dict["id"], user_id=user.id).first()
            except Exception as e:
                current_app.logger.error(e)
                return jsonify(errno=RET.DBERR, errmsg="评论点赞对象查询异常")
            if comment_like_obj:
                comment_dict["is_like"] = True
            else:
                comment_dict["is_like"] = False

    # ------------7. 查询当前作者信息,进行展示-------------
    is_followed = False
    # 查询当前用户所关注的人的id列表
    followed_id = []
    if user:
        for user_followed in user.followed:
            followed_id.append(user_followed.id)
        if news.user_id in followed_id:
            is_followed = True

    # 返回的数据字典
    data = {
        "user": user.to_dict() if user else None,
        "click_rank_list": click_news_list,
        "news": news_dict,
        "is_collected": is_collected,
        "is_followed": is_followed,
        "comments": comments_dict_list
    }

    return render_template("news/detail.html", data=data)


@news_bp.route('/news_collect', methods=['POST'])
@user_login_data
def news_collect():
    """新闻收藏 后端接口"""
    """
    0.判断用户是否登陆
    1.获取参数
        news_id:当前新闻id  action:要执行的操作
    2.数据校验
        2.1 非空判断
        2.2 action格式校验
    3.逻辑处理
        3.1 根据news_id查询news对象
        3.2 判断操作  collect:将新闻id添加到用户的collect_news中
                     cancel_collect:将新闻id从用户的collect_news中删除
    4.返回结果
    """
    # 1.获取参数
    user = g.user
    news_id = request.json.get("news_id")
    action = request.json.get("action")
    # 2.1 非空判断
    if not user:
        current_app.logger.error("用户未登录")
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    if not all([news_id, action]):
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 2.2action格式校验
    if action not in ["collect", "cancel_collect"]:
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 3.1 根据news_id查询news对象
    try:
        news = News.query.filter_by(id=news_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询新闻数据异常")
    if not news:
        current_app.logger.error("新闻数据不存在")
        return jsonify(errno=RET.DBERR, errmsg="新闻数据不存在")
    # 3.2 判断操作
    if action == "collect":
        user.collection_news.append(news)
    else:
        if news in user.collection_news:
            user.collection_news.remove(news)
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存收藏新闻异常")

    return jsonify(errno=RET.OK, errmsg="操作成功")


@news_bp.route('/news_comment', methods=['POST'])
@user_login_data
def news_comment():
    """新闻主评论,子评论 后端接口"""
    """
    1.获取参数
        news_id: 要评论的新闻id   comment: 评论内容   parent_id: 父评论id    user: 当前登陆用户
    2.参数校验
    3.逻辑处理
        3.1 根据news_id查询news对象
        3.2 将评论添加到数据库中
    4.返回结果
    """
    # 1.获取参数
    user = g.user
    news_id = request.json.get("news_id")
    content = request.json.get("content")
    parent_id = request.json.get("parent_id")
    # 2.参数校验
    if not user:
        current_app.logger.error("用户未登录")
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    if not all([news_id, content]):
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    try:
        news = News.query.filter_by(id=news_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="新闻数据查询异常")
    if not news:
        current_app.logger.error("该条新闻不存在")
        return jsonify(errno=RET.NODATA, errmsg="该条新闻不存在")
    # 3.逻辑处理
    # 创建评论对象,保存评论信息
    comment = Comment()
    comment.news_id = news_id
    comment.user_id = user.id
    comment.content = content
    if parent_id:
        comment.parent_id = parent_id
    # 将评论对象保存到数据库中
    try:
        db.session.add(comment)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存评论对象异常")
    return jsonify(errno=RET.OK, errmsg="评论成功", data=comment.to_dict())


@news_bp.route('/comment_like', methods=['POST'])
@user_login_data
def comment_like():
    """评论的点赞,取消点赞 后端接口"""
    """
    1.获取参数
        comment_id: 操作的评论的id    action: 要执行的操作
    2.参数校验
        2.1 非空判断(无user时,先登陆)
        2.2 action格式校验
    3.逻辑处理
        3.1 根据comment_id查询对应评论对象
        3.2 根据comment_id查询对应评论点赞对象
        3.3 判断是点赞还是取消点赞
            3.3.1 点赞
                1.判断是否没有点赞
                2.创建评论点赞对象; 设置对象参数: comment_id, user_id; 将更新提交到数据库
            3.3.2 取消点赞
                1.判断是否已经点赞
                2.删除数据库中对应数据
    4.返回结果
    """
    # 1.获取参数
    user = g.user
    comment_id = request.json.get("comment_id")
    action = request.json.get("action")
    # 2.1 非空判断(无user时,先登陆)
    if not user:
        current_app.logger.error("用户未登录")
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    if not all([comment_id, action]):
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 2.2 action格式校验
    if action not in ["add", "remove"]:
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 3.1 根据comment_id查询对应评论对象
    try:
        comment = Comment.query.get(comment_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询评论数据异常")
    if not comment:
        current_app.logger.error("该条评论不存在")
        return jsonify(errno=RET.DBERR, errmsg="该条评论不存在")
    # 3.2 根据comment_id查询对应评论点赞对象列表
    try:
        is_comment_like = CommentLike.query.filter_by(comment_id=comment_id, user_id=user.id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="查询评论点赞数据异常")
    # 3.3 判断是点赞还是取消点赞
    if action == "add":
        if not is_comment_like:
            comment_like_obj = CommentLike()
            comment_like_obj.comment_id = comment_id
            comment_like_obj.user_id = user.id
            # 评论的点赞数加1
            comment.like_count += 1
            db.session.add(comment_like_obj)
    else:
        if is_comment_like:
            db.session.delete(is_comment_like)
            # 评论的点赞数减1
            comment.like_count -= 1
    # 提交数据
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存收藏新闻异常")

    return jsonify(errno=RET.OK, errmsg="操作成功")


@news_bp.route('/followed_user', methods=['POST'])
@user_login_data
def followed_user():
    """用户的关注/取消关注"""
    """
    1.获取参数
        author_id: 操作的评论的id    action: 要执行的操作
    2.参数校验
        2.1 非空判断(无user时,先登陆)
        2.2 action格式校验
    3.逻辑处理
        3.1 根据author_id和user.id判断关系表中的是否有对应数据
        3.2 判断是否已经关注
            3.2.1 已经关注
                1.判断action是否是取消关注
                2.删除关注列表中对应的数据
            3.2.2 没有关注
                1.判断action是否为关注
                2.将作者id添加到用户关注列表中
    4.返回结果
    """
    # 1.获取参数
    user = g.user
    author_id = request.json.get("author_id")
    action = request.json.get("action")
    # 2.1 非空判断(无user时,先登陆)
    if not user:
        current_app.logger.error("用户未登录")
        return jsonify(errno=RET.SESSIONERR, errmsg="用户未登录")
    if not all([author_id, action]):
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 2.2 action格式校验
    if action not in ["follow", "unfollow"]:
        current_app.logger.error("参数错误")
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 3.1 根据author_id和user.id判断关系表中的是否有对应数据
    # 更具author_id查询出用户对象
    try:
        author = User.query.filter_by(id=author_id).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="作者对象查询异常")
    if not author:
        current_app.logger.error("该作者不存在")
        return jsonify(errno=RET.DBERR, errmsg="该作者不存在")
    # 用户关注表中用户id等于作者id的数据对象
    followed = user.followed.filter(User.id == author_id).first()
    # 已经关注 --> 取消关注
    if followed:
        if action == "unfollow":
            user.followed.remove(author)
    # 没有关注 --> 添加关注
    else:
        if action == 'follow':
            user.followed.append(author)
    # 提交数据
    try:
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        # 数据库回滚
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="保存用户关注异常")

    return jsonify(errno=RET.OK, errmsg="操作成功")






